﻿package com.zouloux.ui
{
	import com.zouloux.abstract.IScrollView;
	import com.zouloux.events.ScrollEvent;
	import com.zouloux.ui.Scroll;
	import flash.display.DisplayObject;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Matrix;
	import com.greensock.TweenLite;
	
	public class ScrollView extends Component implements IScrollView
	{
		// Les éléments graphiques
		public var $slider							:Sprite;
		public var $back							:Sprite;
		public var $mask							:Sprite;
		public var $up								:Sprite;
		public var $down							:Sprite;
		
		// Définit la hauteur minimum du slider
		public var maxSliderSize					:uint					= 15;
		
		// La hauteur de contenu
		protected var _contentHeight				:Number					= 0;
		
		// La hauteur de la scroll
		protected var _totalHeight					:Number					= 0;
		
		// La position actuelle
		protected var _position						:Number					= 0;
		
		// La position du curseur par rapport à la barre
		protected var _barMouseY					:Number;
		
		// Définit si on est en train de se déplacer
		protected var _dragging						:Boolean;
		
		// L'espace entre le scroll et le target
		protected var _gap							:Number;
		private var _upButton:Boolean;
		private var _downButton:Boolean;
		
		
		// Les getters
		public function get contentHeight ():Number
		{
			return _contentHeight;
		}
		public function get totalHeight ():Number
		{
			return _totalHeight;
		}
		public function get position ():Number
		{
			return _position;
		}
		public function get gap ():Number
		{
			return _gap;
		}
		
		
		// Les setters
		public function set contentHeight (value:Number):void
		{
			_contentHeight = value;
			refresh();
		}
		public function set totalHeight (value:Number):void
		{
			_totalHeight = value;
			refresh();
		}
		public function set position (value:Number):void
		{
			_position = value;
			update();
		}
		public function set gap (value:Number):void
		{
			_gap = value;
		}
		public function set upButton (value:Boolean):void
		{
			_upButton = value;
			/*
			if (value)
			{
				if ()
				{
					$up = createButton(15, 15, true);
					addChild($up)
				}
			}
			else if ()
			{
				
			}*/
		}
		public function set downButton (value:Boolean):void
		{
			_downButton = value;
		}
		
		
		// Le constructeur
		public function ScrollView ()
		{
			// Ecouter les ajouts et les suppressions du stage
			addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true);
			addEventListener(Event.REMOVED_FROM_STAGE, dispose, false, 0, true);
			
			// Vérifier si le back existe
			if ($back == null)
				createBack();
			
			// Vérifier si la barre existe
			if ($slider == null)
			{
				$slider = createButton(15, 30, false);
				addChild($slider);
			}
			
			var upBtn:GenericButton = createButton(15, 15, true);
			
			var downBtn:GenericButton = createButton(15, 15, true);
			downBtn.rotation = -90;
			downBtn.x += 15;
			downBtn.y += 15;
			
			addChild(upBtn);
			addChild(downBtn);
		}
		
		// Créer le fond
		protected function createBack ():void
		{
			$back = new Sprite();
			$back.graphics.beginFill(0xBBBBBB, 1);
			$back.graphics.drawRect(0, 0, 15, 100);
			$back.graphics.endFill();
			addChildAt($back, 0);
		}
		
		// Créer un bouton
		protected function createButton (width:Number, height:Number, arrow:Boolean = true):Sprite
		{
			button = new GenericButton();
			button.graphics.beginGradientFill("linear", [0xFFFFFF, 0xDDDDDD], [1, 1], [0, 255], new Matrix());
			button.graphics.drawRect(0, 0, w, h);
			button.graphics.endFill();
			
			if (arrow)
			{
				button.graphics.beginFill(0x000000, 1);
				button.graphics.moveTo(5, 5);
				button.graphics.lineTo(7.5);
				button.graphics.lineTo();
				button.graphics.endFill();	
			}
			
			return button;
		}
		
		// L'init
		protected function init (event:Event):void
		{
			//removeEventListener(Event.ADDED_TO_STAGE, init);
			$slider.addEventListener(MouseEvent.MOUSE_DOWN, startBarDrag, false, 0, true);
			$back.addEventListener(MouseEvent.MOUSE_DOWN, startBarDrag, false, 0, true);
			stage.addEventListener(MouseEvent.MOUSE_UP, stopBarDrag, false, 0, true);
		}
		
		// Une fois que ce clip n'est plus dans la displayList
		private function dispose (event:Event = null):void
		{
			//removeEventListener(Event.REMOVED_FROM_STAGE, kill);
			$slider.removeEventListener(MouseEvent.MOUSE_DOWN, startBarDrag);
			$back.addEventListener(MouseEvent.MOUSE_DOWN, startBarDrag, false, 0, true);
			stage.removeEventListener(MouseEvent.MOUSE_UP, stopBarDrag);
		}
		
		// La méthode pour mettre à jours la taille du scroll
		public function refresh ():void
		{
			// On update la taille du fond
			$back.height = _totalHeight;
			
			// Si le masque existe, pour lui aussi
			if ($mask != null)
				$mask.height = _totalHeight;
			
			// On calcule le ratio
			var r:Number = (_totalHeight / _contentHeight);
			var h:Number = r * _totalHeight;
			
			// On place le slider grâce à ce ratio, limiter à la taille spécifiée
			$slider.height = Math.min(h, Math.max(_totalHeight, maxSliderSize));
			
			// On actualise le curseur
			update();
			
			// Détecter si on a besoin du scroll
			($slider.height >= _totalHeight) ? hide() : show();
		}
		
		// La méthode pour démarrer le drag
		protected function startBarDrag (event:MouseEvent):void
		{
			// Calculer la position du curseur sur le slider
			_barMouseY = mouseY - $slider.y;
			
			// On se déplace
			_dragging = true;
			stage.addEventListener(MouseEvent.MOUSE_MOVE, barDragging);
		}
		
		// La boucle
		protected function barDragging (event:MouseEvent):void
		{
			// Adapter la position de la barre, avec les limites
			$slider.y = Math.max(0, Math.min(_totalHeight - $slider.height, mouseY - _barMouseY));
			
			// Créer l'event
			var scrollEvent:ScrollEvent = new ScrollEvent(ScrollEvent.SCROLL);
			
			// Spécifier la nouvelle position
			scrollEvent.position = ($slider.y / _totalHeight) * (_totalHeight / (_totalHeight - $slider.height));
			
			// Dispatcher l'event
			dispatchEvent(scrollEvent);
			
			// Rendre fluide
			event.updateAfterEvent();
		}
		
		// La méthode pour arrêter le drag
		protected function stopBarDrag (event:MouseEvent):void
		{
			// On arrête les déplacements
			stage.removeEventListener(MouseEvent.MOUSE_MOVE, barDragging);
			_dragging = false;
		}
		
		// La méthode pour updater le curseur
		public function update (event:Event = null):void
		{
			// Si on est pas en train de se déplacer
			if (!_dragging)
			{
				// Actualiser la position du curseur
				$slider.y = Math.max(0, Math.min((_position / (_totalHeight / (_totalHeight - $slider.height))) * _totalHeight, _totalHeight - $slider.height));
			}
		}
		
		// Afficher cette scrollBar
		public function show ():void
		{
			// On autorise les interaction
			mouseEnabled = true;
			mouseChildren = true;
			
			// On rend visible
			visible = true;
			
			// Et on affiche progressivement
			TweenLite.to(this, .8, {alpha:1});
		}
		
		// Masquer cette scrollBar
		public function hide ():void
		{
			// On interdit les interactions
			mouseEnabled = true;
			mouseChildren = true;
			
			// On masque progressivement
			TweenLite.to(this, .8, { alpha:0, onComplete:function()
			{
				// Puis rend invisible
				visible = false;
			}});
		}
		
		// On monte
		public function up (event:MouseEvent = null):void
		{
			
		}
		
		// Et on descend
		public function down (event:MouseEvent = null):void
		{
			
		}
	}
}